/*
 * $Id: icmp_checksum.c 16f2bd2b4e2c 2012/12/15 22:47:51 pgurumur $
 * Copyright (c) 2012 Prabhu Gurumurthy <pgurumur@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * File icmp_checksum.c generated on Sunday December 09, 2012 @11:50:30 PST
 *
 */ 
/* __version__  = "$Revision: 16f2bd2b4e2c $" */
/* __author__   = "$Author: pgurumur $"   */
/* __modified__ = "$Date: 2012-12-15 22:47:51Z $"     */
#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>

#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void);
int in_cksum(u_short *, int);

/*
 * in_cksum --
 * Checksum routine for Internet Protocol family headers (C Version)
 */
int
in_cksum(u_short *addr, int len)
{
   int nleft = len;
   u_short *w = addr;
   int sum = 0;
   u_short answer = 0;

   printf("%d: %d\n", len, *w);

   /*
    * Our algorithm is simple, using a 32 bit accumulator (sum), we add
    * sequential 16 bit words to it, and at the end, fold back all the
    * carry bits from the top 16 bits into the lower 16 bits.
    */
   while (nleft > 1)  {
      sum += *w++;
      printf("%d: %d\n", sum, nleft);
      nleft -= 2;
      printf("%d\n", nleft);
   }

   /* mop up an odd byte, if necessary */
   if (nleft == 1) {
      *(u_char *)(&answer) = *(u_char *)w ;
      sum += answer;
   }

   /* add back carry outs from top 16 bits to low 16 bits */
   sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
   sum += (sum >> 16);        /* add carry */
   answer = ~sum;          /* truncate to 16 bits */
   return(answer);
}

int
main()
{
   u_char pkthdr[65535];
   int datalen = 64 - 8;
   memset(pkthdr, '\0', sizeof(pkthdr));

   u_char *packet = pkthdr + sizeof(struct ip);
   struct icmp *icp = (struct icmp *)packet;
   icp->icmp_type = ICMP_ECHO;
   icp->icmp_code = 0;
   icp->icmp_cksum = 0;
   icp->icmp_seq = 1;
   icp->icmp_id = getpid() & 0xFFFF;

   int cc = datalen + 8;
   icp->icmp_cksum = in_cksum((u_short *)icp, cc);

   printf("%d\n", icp->icmp_cksum);

   return 0;
}
